import WxPay from 'wechatpay-node-v3';
import Decimal from 'decimal.js';
import { WECHAT_PAY_MANAGER } from 'nest-wechatpay-node-v3';
import {
  HttpStatus,
  Inject,
  Injectable,
  InternalServerErrorException,
} from '@nestjs/common';
import {
  ERROR_DECODE_FAILED,
  ERROR_PAY_ORDER_CREATE_FAILED,
  ERROR_VERIGFY_SIGN_FAILED,
} from '@/common/constant';
import { WepayCallbackDto } from './dto/wepay.callback.dto';
import configuration from 'config/configuration';

/**
 * 更多信息请参考
 * 支付结果通知：https://pay.weixin.qq.com/docs/merchant/apis/in-app-payment/payment-notice.html
 * 退款结果通知：https://pay.weixin.qq.com/docs/merchant/apis/in-app-payment/refund-result-notice.html
 */
interface IPaidDetail {
  /**
   * 支付状态
   * SUCCESS：支付成功
   */
  trade_state: string;

  /**
   * 退款状态
   * SUCCESS：退款成功
   */
  refund_status: string;

  /**
   * 商户系统内部订单号，总订单Id
   */
  out_trade_no: string;

  /**
   * 商户退款单号，对应子订单的退款单号
   */
  out_refund_no: string;
}

@Injectable()
export class WepayService {
  constructor(@Inject(WECHAT_PAY_MANAGER) private wepay: WxPay) { }

  /**
   * 创建微信预支付订单
   * @param detail.price 订单金额
   * @param detail.id 订单id，保证在系统中唯一
   * @param detail.description 订单描述
   * @param detail.openId 用户openid
   * @param detail.callbackUrl 回调地址
   * @returns 预支付id
   */
  async CreateOrderWX(detail: {
    price: number;
    id: string;
    description: string;
    openId: string;
    callbackUrl: string;
  }): Promise<string> {
    // 验证价格是否有效
    if (!detail.price || isNaN(detail.price) || detail.price < 0.01) {
      console.error(`支付金额无效: ${detail.price}，自动设置为0.01元`);
      detail.price = 0.01;
    }

    try {
      const params = {
        description: detail.description,
        out_trade_no: detail.id,
        notify_url: detail.callbackUrl,
        amount: {
          total: Math.round(new Decimal(detail.price).mul(100).toNumber()),
          currency: 'CNY'
        },
        payer: {
          openid: detail.openId,
        },
      };

      console.log('微信支付请求参数:', JSON.stringify(params));
      const res = await this.wepay.transactions_jsapi(params);

      if (res.status !== 200) {
        console.error('微信支付创建失败:',
          '状态码:', res.status,
          '响应数据:', res.data,
          '完整响应:', JSON.stringify(res)
        );
        throw new InternalServerErrorException(`支付订单创建失败: ${res.status} ${JSON.stringify(res.data || {})}`);
      }

      console.log('微信支付响应成功:', JSON.stringify(res.data));
      return res.data.package;
    } catch (error) {
      // 记录完整错误信息
      console.error('微信支付异常:',
        error.message,
        error.response?.data ? JSON.stringify(error.response.data) : '',
        '原始错误:', error
      );
      throw new InternalServerErrorException(
        error.response?.data?.message || error.message || ERROR_PAY_ORDER_CREATE_FAILED
      );
    }
  }

  /**
   * 退款
   * @param detail.id 支付时的订单id
   * @param detail.refundId 退款id，保证在系统中唯一
   * @param detail.totalPrice 订单总金额
   * @param detail.refundPrice 退款金额
   * @param detail.callbackUrl 回调地址
   * @returns 是否退款成功
   */
  async RefundedOrderWX(detail: {
    id: string;
    refundId: string;
    totalPrice: number;
    refundPrice: number;
    callbackUrl: string;
  }) {
    const params = {
      out_trade_no: detail.id,
      out_refund_no: detail.refundId,
      notify_url: detail.callbackUrl,
      amount: {
        total: new Decimal(detail.totalPrice).mul(100).toNumber(),
        refund: new Decimal(detail.refundPrice).mul(100).toNumber(),
        currency: 'CNY',
      },
    };
    const res = await this.wepay.refunds(params);
    return res.status === HttpStatus.OK;
  }

  /**
   * 签名校验
   */
  async verifySign(headers: Record<string, string>, body: any) {
    const params = {
      timestamp: headers['wechatpay-timestamp'],
      nonce: headers['wechatpay-nonce'],
      body: body,
      serial: headers['wechatpay-serial'],
      signature: headers['wechatpay-signature'],
    };
    const result = await this.wepay.verifySign(params);
    if (!result)
      throw new InternalServerErrorException(ERROR_VERIGFY_SIGN_FAILED);
  }

  /**
   * 回调解密
   */
  decipherGcm(wepayCallbackDto: WepayCallbackDto) {
    const detail = this.wepay.decipher_gcm<IPaidDetail>(
      wepayCallbackDto.resource.ciphertext,
      wepayCallbackDto.resource.associated_data,
      wepayCallbackDto.resource.nonce,
      configuration.wechat.apiV3Key,
    );
    // if (detail.refund_status !== 'SUCCESS')
    //   throw new InternalServerErrorException(ERROR_DECODE_FAILED);
    return detail;
  }

  /**
   * 小程序调起支付签名计算
   */
  getSignature(
    appId: string,
    timeStamp: string,
    nonceStr: string,
    packageStr: string,
  ) {
    const str = [appId, timeStamp, nonceStr, packageStr, ''].join('\n');
    return this.wepay.sha256WithRsa(str);
  }
}
